package server;

import java.io.BufferedReader;
import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.util.SortedMap;

import protocol.Protocol;
import tokenizer.NewLineTokenizer;
import tokenizer.Tokenizer;

public class SocketThread implements Runnable {
	private Protocol prot;
	private SocketChannel sock;
	private Socket sock2;
	private Tokenizer ProtocolToken;
	private Tokenizer selfToken;

	public SocketThread(SocketChannel sock, Protocol prot) {
		this.prot = prot;
		this.sock = sock;

		ProtocolToken = prot.getTokenizer();
		SortedMap<String, Charset> map = Charset.availableCharsets();
		selfToken = new NewLineTokenizer("T", map.get("UTF-8"));
		map=null;
	}
	public SocketThread(Socket sockk, Protocol prot2) {
		this.prot = prot2;
		this.sock2 = sockk;

		ProtocolToken = prot.getTokenizer();
		SortedMap<String, Charset> map = Charset.availableCharsets();
		selfToken = new NewLineTokenizer("T", map.get("UTF-8"));
		map=null;
	}
	@Override
	public void run() {
	try {
		Blocking();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	System.out.println("closing");
	try {
		sock2.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	//nonBlocking();
}
	private void nonBlocking() {
		try {
			System.out.println("new Thread with:" + sock.getRemoteAddress().toString());
			sock.configureBlocking(false);
		} catch (IOException e3) {
			// TODO Auto-generated catch block
			e3.printStackTrace();
		}
		
		ByteBuffer outbuff = ByteBuffer.allocate(512);
		ByteBuffer inbuff= ByteBuffer.allocate(512);

		while(!prot.isEnd() && sock.isOpen() &&  sock.isConnected())
		{
			
			try {
				int i = sock.read(inbuff);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}						
			selfToken.addBytes(inbuff);
			//inbuff.clear();
			System.out.println(selfToken.toString());
			if(selfToken.hasMessage())
			{
				String temp = selfToken.nextMessage();
				//System.out.println("msg " + temp + selfToken.toString());
				if(temp!=null)
				prot.ParseMsg(temp);
			}
		//	System.out.println(ProtocolToken.hasMessage());
			if(ProtocolToken.hasMessage())
			{
				System.out.println("sending reply");
				try {
					outbuff=ProtocolToken.getBytesForMessage(ProtocolToken.nextMessage());
				} catch (CharacterCodingException e2) {
					// TODO Auto-generated catch block
					e2.printStackTrace();
				}
				try {
					while(outbuff.hasRemaining())
					sock.write(outbuff);
					outbuff.clear();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
		try {
			System.out.println("thread closed with:" + sock.getRemoteAddress().toString());
			sock.close();
		} catch (IOException e3) {
			// TODO Auto-generated catch block
			e3.printStackTrace();
		}
		

	}
		
	
	private void Blocking() throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(sock2.getInputStream()));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(sock2.getOutputStream()));
		while(!prot.isEnd() &&  sock2.isConnected())
		{
		prot.ParseMsg(in.readLine());
		if(ProtocolToken.hasMessage())
		{
			System.out.println("printing");
			out.print(ProtocolToken.nextMessage());	
		}
		
		}
		sock2.close();
		
		
	}
}